<template>
  <div class="page-content">
    <div class="header">
      <slot name="header">
        <!-- 在不使用具名插槽时默认显示的内容 -->
        <h3>{{ tableTitle }}</h3>
        <div class="handler">
          <el-button
            icon="el-icon-refresh"
            size="mini"
            class="handler-icon"
            type="success"
            @click="handleRefreshBtnClick"
            >刷新
          </el-button>
          <el-button
            v-if="isCreate"
            icon="el-icon-circle-plus"
            size="mini"
            class="handler-icon"
            @click="handleCreateBtnClick"
            >添加
          </el-button>
        </div>
      </slot>
    </div>
    <red-table
      :dataList="list"
      :dataListCount="count"
      v-bind="tableConfig"
      v-model:page="pageInfo"
      :isCreate="isCreate"
    >
      <!-- 使用具名,作用域插槽status -->
      <template #status="scope">
        <el-button
          :type="scope.row.enable || scope.row.status ? 'success' : 'danger'"
          size="mini"
          plain
        >
          {{ scope.row.enable || scope.row.status ? '启用' : '禁用' }}
        </el-button>
      </template>
      <!-- 使用具名,作用域插槽createAt -->
      <template #createAt="scope">
        <span>{{ $filter.formatTime(scope.row.createAt) }}</span>
      </template>
      <!-- 使用具名,作用域插槽updateAt -->
      <template #updateAt="scope">
        <span>{{ $filter.formatTime(scope.row.updateAt) }}</span>
      </template>
      <!-- 使用具名,作用域插槽handler -->
      <template #handler="scope">
        <div class="handler-btns">
          <el-button
            v-if="isUpdate"
            size="mini"
            icon="el-icon-edit"
            type="text"
            @click="handleEditBtnClick(scope.row)"
            >编辑
          </el-button>
          <el-button
            v-if="isDelete"
            size="mini"
            icon="el-icon-delete"
            type="text"
            @click="handleDeleteBtnClick(scope.row)"
          >
            删除
          </el-button>
        </div>
      </template>
      <!-- 使用具名,作用域插槽image -->
      <template #image="scope">
        <div class="demo-image__preview">
          <el-image
            style="width: 60px; height: 80px"
            :src="scope.row.imgUrl"
            :preview-src-list="[scope.row.imgUrl]"
          >
          </el-image>
        </div>
      </template>
      <!-- 注册特殊插槽, 供第一页面直接使用. 注意这里是注册插槽 -->
      <!-- 这里使用了一个插槽, 为了得到的插槽的scope给正真需要使用的人使用. ??? 这里我也不理解 -->
      <template
        v-for="item in peculiarSlot"
        :key="item.prop"
        #[item.slotName]="scope"
      >
        <slot :name="item.slotName" :row="scope.row"></slot>
      </template>
    </red-table>
  </div>
</template>

<script lang="ts">
import { defineComponent, computed, ref, watch } from 'vue';
import { useStore } from '@/store';

import { ElMessageBox } from 'element-plus';

import redTable from '@/base-ui/table';
import { useMessageInfo, useMessageSuccess } from '@/hooks/use-message';
import { usePermission } from '@/hooks/use-permission';
import emitter from '@/utils/eventBus';
import { PAGECONTENTRELOAD } from '@/utils/eventBus/constant';

export default defineComponent({
  props: {
    // 作为url
    pageName: {
      type: String,
      required: true
    },
    tableConfig: {
      type: Object,
      default: () => {}
    }
  },
  components: {
    redTable
  },
  setup(props, { emit }) {
    // 获取tableTitleName
    const tableTitle = ref(props.tableConfig.tableTitle);
    // 0.获取用户能使用的按钮的权限
    const isCreate = usePermission(props.pageName, 'create');
    const isDelete = usePermission(props.pageName, 'delete');
    const isUpdate = usePermission(props.pageName, 'update');
    const isQuery = usePermission(props.pageName, 'query');
    const store = useStore();
    // 3.table的换页操作
    // 从red-table里面发送过来一个事件，update:page，但是我们不需要去监听。因为我们使用的是v-model的形式传递，用ref的形式包裹数据。v-model会自己监听这个事件，ref会让数据变为响应式，v-model的事件把值修改ref就会立刻更新这些数据。
    const pageInfo = ref({ currentPage: 1, pageSize: 10 });
    let queryMoreInfo: any; // 这是点击搜索按钮是获取的最新form表单的内容, 我们在点击换页时也需要使用到.
    // 根据变化重新发送请求，获取新的数据。
    watch(pageInfo, () => {
      //  我们需要带着search的值切换page.
      getPageContentList(queryMoreInfo);
    });

    // 1.去action里面发送请求,储存在state里面
    const getPageContentList = (queryInfo: any = {}) => {
      queryMoreInfo = queryInfo; // 放在外部保存起来,因为换页按钮还要使用.
      if (!isQuery) return; // 如果这个用户不能使用查询,则直接返回 意思是你不能使用搜索.
      store.dispatch('commonModule/getPageListAction', {
        pageUrl: `/${props.pageName}/list`,
        pageName: props.pageName,
        queryInfo: {
          // 为什么offset需要currentPage-1, 因为我们显示是从第1页而不是0页. 0 * currentPage从0开始加载size条, 1 * currentPage从这里开始加载size条,这样才能对的上.
          offset: (pageInfo.value.currentPage - 1) * pageInfo.value.pageSize, // 总共显示了多少条数据
          size: pageInfo.value.pageSize,
          ...queryMoreInfo
        }
      });
    };
    getPageContentList(); // 页面加载时执行一次
    // 监听外部传进来的事件,刷新table内容
    emitter.on(PAGECONTENTRELOAD, () => {
      getPageContentList();
    });

    // 2.去vuex拿到需要的数据, 由computed只要里面的数据有变化我就会更新我的数据.
    const list = computed(() =>
      store.getters[`commonModule/pageList`](props.pageName)
    );
    const count = computed(() =>
      store.getters[`commonModule/pageListCount`](props.pageName)
    );

    // 4.动态注册特殊插槽, 该页面特有的插槽, 特殊需求. 我们不应该每有一个页面有特殊数据就往page-content里面放, 这里应该放的是一些公共的数据.
    // 排除公共插槽. 把你的特殊插槽写在你自己的页面即可.如goods,user
    // 上面写好的公共的插槽一定要在这里排除不然会再生成一个一摸一样的, 只要配置文件里面写了slotName这个属性.
    const peculiarSlot = props.tableConfig.propList.filter((item: any) => {
      if (item.slotName === 'createAt') return false;
      if (item.slotName === 'updateAt') return false;
      if (item.slotName === 'status') return false;
      if (item.slotName === 'image') return false;
      if (item.slotName === 'handler') return false;
      return true;
    });

    // 5.刷新/删除/编辑/添加按钮的操作,下面的函数都是通用的,每个table页面都可以使用.
    // 刷新按钮
    const handleRefreshBtnClick = () => {
      getPageContentList(); // 重新获取最新数据
      useMessageInfo({ message: '刷新成功' });
    };
    // 删除显示dialog
    const handleDeleteBtnClick = (item: any) => {
      ElMessageBox.confirm('确认删除这条数据 ?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          // 点击确认后
          store.dispatch('commonModule/deletePageListAction', [
            props.pageName,
            item.id
          ]);
          getPageContentList(); // 重新获取最新数据
          // 操作成功
          useMessageSuccess({
            message: '删除成功'
          });
        })
        .catch(() => {
          useMessageInfo({
            message: '操作取消'
          });
        });
    };

    // 点击添加后显示dialog,dialog确定后执行真正操作
    const handleCreateBtnClick = () => {
      emit('pageContentCreateBtnClick');
    };
    // 编辑按钮显示dialog,dialog确定后执行真正操作
    const handleEditBtnClick = (item: any) => {
      emit('pageContentEditBtnClick', item);
    };

    return {
      tableTitle,
      list,
      count,
      getPageContentList,
      pageInfo,
      peculiarSlot,
      isCreate,
      isUpdate,
      isDelete,
      handleRefreshBtnClick,
      handleDeleteBtnClick,
      handleCreateBtnClick,
      handleEditBtnClick
    };
  }
});
</script>

<style scoped lang="less">
.page-content {
  position: relative;
  border-top: 10px solid #f0f2f5;
  .header {
    margin: 20px 0;
    h3 {
      padding-left: 20px;
    }
    .handler {
      position: absolute;
      top: 15px;
      right: 20px;
      .handler-icon {
        height: 36px;
      }
    }
  }
}
</style>
